package com.example.ibsp_demo.utils;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import java.util.Base64;

public class PasswordUtils {
    // 盐值长度（字节）
    private static final int SALT_LENGTH = 16;
    // 密钥长度（位）
    private static final int KEY_LENGTH = 256;
    // 迭代次数（增加可提高安全性但降低性能）
    private static final int ITERATIONS = 65536;
    // 算法名称
    private static final String ALGORITHM = "PBKDF2WithHmacSHA256";

    /**
     * 生成密码哈希（带盐值）
     * @param password 明文密码
     * @return 格式为：算法:迭代次数:盐值:哈希值
     * @throws Exception 加密过程中可能的异常
     */
    public static String hashPassword(String password) throws Exception {
        SecureRandom random = SecureRandom.getInstanceStrong();
        byte[] salt = new byte[SALT_LENGTH];
        random.nextBytes(salt);

        byte[] hash = deriveKey(password.toCharArray(), salt, ITERATIONS, KEY_LENGTH);

        // 格式：算法:迭代次数:盐值:哈希值
        return String.format("%s:%d:%s:%s",
                ALGORITHM,
                ITERATIONS,
                Base64.getEncoder().encodeToString(salt),
                Base64.getEncoder().encodeToString(hash)
        );
    }

    /**
     * 验证密码
     * @param password 明文密码
     * @param storedHash 存储的哈希值
     * @return 密码是否匹配
     * @throws Exception 验证过程中可能的异常
     */
    public static boolean verifyPassword(String password, String storedHash) throws Exception {
        String[] parts = storedHash.split(":");
        if (parts.length != 4) {
            throw new IllegalArgumentException("无效的哈希格式");
        }

        String algorithm = parts[0];
        int iterations = Integer.parseInt(parts[1]);
        byte[] salt = Base64.getDecoder().decode(parts[2]);
        byte[] hash = Base64.getDecoder().decode(parts[3]);

        byte[] testHash = deriveKey(password.toCharArray(), salt, iterations, KEY_LENGTH);

        return slowEquals(hash, testHash);
    }

    /**
     * 生成密钥（PBKDF2算法）
     * @param password 密码字符数组
     * @param salt 盐值
     * @param iterations 迭代次数
     * @param keyLength 密钥长度
     * @return 生成的密钥字节数组
     * @throws Exception 生成过程中可能的异常
     */
    private static byte[] deriveKey(char[] password, byte[] salt, int iterations, int keyLength) throws Exception {
        PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength);
        SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
        return factory.generateSecret(spec).getEncoded();
    }

    /**
     * 安全比较两个字节数组（防止时序攻击）
     * @param a 第一个字节数组
     * @param b 第二个字节数组
     * @return 两个数组是否相等
     */
    private static boolean slowEquals(byte[] a, byte[] b) {
        int diff = a.length ^ b.length;
        for(int i = 0; i < a.length && i < b.length; i++)
            diff |= a[i] ^ b[i];
        return diff == 0;
    }

    // 示例用法
    public static void main(String[] args) {
        try {
            //假设这是前端传入的输入密码，通过hashPassword加密后set存储就行了
            String password = "123456";

            // 加密密码
            String hashedPassword = hashPassword(password);
            System.out.println("加密后的密码: " + hashedPassword);

            // 验证密码
            boolean isCorrect = verifyPassword(password, hashedPassword);
            System.out.println("密码验证结果: " + isCorrect); // 输出: true

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
